/*
 * Licensed to the Tai Ping Jin Ke
 *
 * Copyright (c) 2022 .
 * All rights reserved.
 * 项目名称：太平金科-基础组件封装层-SpringBoot组件封装-缺省实现
 * 版权说明：本软件属太平金融科技服务(上海)有限公司所有，在未获得太平金融科技服务(上海)有限公司正式授权情况下，任何企业和个人，不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。
 */
package com.taipingframework.boot.web.filters;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.StrPool;
import com.sun.org.apache.xml.internal.utils.FastStringBuffer;
import com.sun.org.apache.xml.internal.utils.StringBufferPool;
import com.taipingframework.boot.web.support.RepeatableRequestWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.springframework.web.util.WebUtils;

import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Slf4j
public class DefaultFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) {
        String key1 = filterConfig.getInitParameter("key1");
        String key2 = filterConfig.getInitParameter("key2");

        String[] stackTraceArray = Arrays.stream(Thread.currentThread().getStackTrace())
                .map(StackTraceElement::toString)
                .toArray(String[]::new);
        log.debug("DefaultFilter.init()， init-param : key1={} ， key2={}\r\n\r\tat {}", key1, key2,
                String.join("\r\n\r\tat ", stackTraceArray[1]));
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.debug("DefaultFilter.doFilter - begin");
        // 检查请求是否为多部分（即文件上传）
        if (ServletFileUpload.isMultipartContent((HttpServletRequest) servletRequest)) {
            RepeatableRequestWrapper requestWrapper = WebUtils.getNativeRequest(servletRequest, RepeatableRequestWrapper.class);
            if (Objects.nonNull(requestWrapper)) {
                Collection<Part> parts = requestWrapper.getParts();
                Map<String, Object> formData = new HashMap<>();
                for (Part part : parts) {
                    if (StringUtils.isNotEmpty(part.getContentType())) {
                        // 附件，此处假设是单文件上传哈
                        formData.putIfAbsent(part.getName(), part.getSubmittedFileName());
                    } else {
                        // 表单字段
                        formData.putIfAbsent(part.getName(), IoUtil.read(part.getInputStream(), StandardCharsets.UTF_8));
                    }
                }
                log.info("文件上传 - 提交表单form-data={}", formData);
            }
        } else {
            //* 记录请求体
            String requestPayload = readRequestPayload(servletRequest);
            if (!(StringUtils.isBlank(requestPayload) || StrPool.EMPTY_JSON.equals(requestPayload))) {
                log.info("读取方式1 - 请求报文message={}", requestPayload);
            }

            String requestBody = readRequestBody(servletRequest);
            if (!(StringUtils.isBlank(requestBody) || StrPool.EMPTY_JSON.equals(requestBody))) {
                log.info("读取方式2 - 请求报文message={}", requestBody);
            }

            String messagePayload = readMessagePayload(servletRequest);
            if (!(StringUtils.isBlank(messagePayload) || StrPool.EMPTY_JSON.equals(messagePayload))) {
                log.info("读取方式3 - 请求报文message={}", messagePayload);
            }
        }

        filterChain.doFilter(servletRequest, servletResponse);

        log.debug("DefaultFilter.doFilter - end");
    }

    @Override
    public void destroy() {
        log.debug("DefaultFilter.destroy");
    }

    /**
     * 方式1 - 读取请求体
     */
    private static String readRequestPayload(ServletRequest servletRequest) throws IOException {
        String payload = StringUtils.EMPTY;

        RepeatableRequestWrapper requestWrapper = WebUtils.getNativeRequest(servletRequest, RepeatableRequestWrapper.class);
        if (Objects.nonNull(requestWrapper)) {
            payload = IoUtil.read(requestWrapper.getInputStream(), Charset.forName(StandardCharsets.UTF_8.name()));
        }

        return payload;
    }

    /**
     * 方式2 - 读取请求体
     */
    private static String readRequestBody(ServletRequest servletRequest) throws IOException {
        String payload = StringUtils.EMPTY;

        RepeatableRequestWrapper requestWrapper = WebUtils.getNativeRequest(servletRequest, RepeatableRequestWrapper.class);
        if (Objects.nonNull(requestWrapper)) {

            String line;
            BufferedReader bufferedReader = requestWrapper.getReader();
            FastStringBuffer fastStringBuffer = StringBufferPool.get();

            while ((line = bufferedReader.readLine()) != null) {
                fastStringBuffer.append(line);
            }
            payload = fastStringBuffer.toString();

            StringBufferPool.free(fastStringBuffer);
        }

        return payload;
    }

    /**
     * 方式3 - 获取请求体
     */
    private static String readMessagePayload(ServletRequest servletRequest) throws IOException {
        String payload = StringUtils.EMPTY;

        RepeatableRequestWrapper requestWrapper = WebUtils.getNativeRequest(servletRequest, RepeatableRequestWrapper.class);
        if (Objects.nonNull(requestWrapper)) {
            byte[] buffer = requestWrapper.getContentAsByteArray();
            payload = new String(buffer, 0, buffer.length, requestWrapper.getCharacterEncoding());
        }

        return payload;
    }

}
